package com.pvdnc.xdynamic.loader.module;

import android.content.Context;
import android.util.Log;

import com.pvdnc.xdynamic.loader.compat.NativeLibraryHelperCompat;
import com.pvdnc.xdynamic.loader.file.FileUtils;
import com.pvdnc.xdynamic.loader.file.MD5;

import java.io.File;
import java.io.IOException;

import dalvik.system.DexClassLoader;

public class ModuleClassLoader {
    private static final String TAG=ModuleClassLoader.class.getSimpleName();

    private Context mContext;

    private DexClassLoader mClassLoader;

    private File mApkFile;

    private File mLibDir;

    private ModuleLoader mLoader;

    public ModuleClassLoader(Context context,ModuleLoader loader) throws IOException {
        mContext=context;
        mLoader=loader;
        //复制文件
        mApkFile=mLoader.getOriginApkFile();
        mLibDir=mLoader.getModuleDir().getLibDir();
        if(shouldCopyModuleFiles()){
            mApkFile=copyModuleApk(mLoader.mApkFile);
            copyLib();
        }
        //加载模块类
       initClassLoader();
    }

    private void initClassLoader() throws IOException {
        Log.d(TAG,"attempt to load module:"+getModuleName()+"'s classes");
        String optDir= mLoader.getModuleDir().getOptDir();
        mClassLoader =new DexClassLoader(mApkFile.getAbsolutePath(),
                optDir,
                mLibDir.getAbsolutePath(),
                mContext.getClassLoader()
        );
    }

    public String getModuleName(){
        return mLoader.getModuleName();
    }

    public static final boolean ALWAYS_COPY=false;

    private boolean shouldCopyModuleFiles() throws IOException {
        if(ALWAYS_COPY) {
            Log.d(TAG,"always copy enabled");
            return true;
        }
        String moduleName = getModuleName();

        File moduleDir = mLoader.getModuleDir().getModuleDir();
        File digestFile = new File(moduleDir, "digest.txt");
        String md5 = MD5.getMD5(mLoader.mApkFile);
        Log.d(TAG,"current MD5:\n\t"+md5);
        if (md5 == null)
            throw new IOException("fail to calculate MD5 for module:"
                    + moduleName);
        if (!digestFile.exists()) {//首次写入
            //写入MD5
            FileUtils.write(digestFile, md5);
            return true;
        }
        //读取并验证MD5
        String oldMD5 = FileUtils.readString(digestFile);
        Log.d(TAG,"old MD5:\n\t"+oldMD5);
        boolean result = !md5.equals(oldMD5);
        Log.d(TAG, "should copy module:" + moduleName + "'s files ? " + result);
        if (result) {//需要更新MD5签名
            FileUtils.write(digestFile, md5);
        }
        return result;
    }

    public File copyModuleApk(File apkFile) throws IOException {
        File targetFile=mLoader.getModuleDir().getModuleApkFile();
        Log.d(TAG,"attempt to copy module:"
                +getModuleName()+" 's apk");
        FileUtils.copy(apkFile,targetFile);
        return targetFile;
    }

    private void copyLib() throws IOException {
        File libDir = mLoader.getModuleDir().getLibDir();
        if (-1 == NativeLibraryHelperCompat.copyNativeBinaries(mApkFile, libDir))
            throw new IOException("fail to copy native lib to dir:" + libDir);
    }

    public ClassLoader getModuleClassLoader(){
        return mClassLoader;
    }

    public Class<?> loadClass(String className) throws ClassNotFoundException {
        return mClassLoader.loadClass(className);
    }
}
